﻿using USNetFramework.Network;
using crypt = Crypt.Common;

namespace USNetFramework.PacketBuilder
{
    /// <summary>
    /// Protobuf网络包构造器
    /// </summary>
    public abstract class PacketBuilder : IPacketBuilder
    {
        /// <summary>
        /// 是否支持扩展包头
        /// </summary>
        public bool m_bUseHeadEx { get; private set; }


        /// <summary>
        /// 加密秘钥
        /// </summary>
        private static string m_sEncryptKey = "ColocasiaTest";


        /// <summary>
        /// 构造一个网络包构造器
        /// </summary>
        public PacketBuilder()
        {
            m_bUseHeadEx = false;
        }


        /// <summary>
        /// 创建一个网络包构造器
        /// </summary>
        /// <param name="inUseHeadEx">是否支持扩展包头</param>
        public PacketBuilder(bool inUseHeadEx = false)
        {
            m_bUseHeadEx = inUseHeadEx;
        }


        /// <summary>
        /// 对Builder进行重置
        /// </summary>
        public void Reset()
        {

        }


        /// <summary>
        /// 对网络包进行编码处理，对网络包头进行序列化处理
        /// </summary>
        /// <param name="packet">网络包</param>
        /// <returns></returns>
        public virtual byte[] Encode(NetPacket packet)
        {
            // 创建一个buffer
            byte[] buffer = new byte[packet.TotalSize];
            NetStream ns = new NetStream(buffer, true);
            ns.Seek(0);
            ns.WriteInt16((short)(packet.TotalSize - NetPacket.NetPacketLenSize));
            ns.WriteByte((byte)packet.RequestType);
            ns.WriteInt32((int)packet.SessionID);
            ns.WriteInt16((short)packet.ProtoType);
            ns.WriteInt16((short)packet.ProtoID);
            ns.WriteBuffer(packet.DataBuffer);
            ns.Close();

            // 如果支持扩展包头
            if (m_bUseHeadEx)
            {
                // 如果支持加密
                if (0 != packet.EncryptType)
                {
                    buffer = Encrypt(buffer, (EnumEncryptType)packet.EncryptType);
                }

                // 如果支持压缩
                if (0 != packet.CompressType)
                {
                    // 暂时不实现
                }

                ushort netSize = (ushort)(buffer.Length + NetPacket.HeadExSize);
                byte[] bufferEx = new byte[netSize];
                NetStream nsEx = new NetStream(bufferEx, true);
                nsEx.WriteInt16((short)(netSize - NetPacket.NetPacketLenSize));
                nsEx.WriteByte(packet.EncryptType);
                nsEx.WriteByte(packet.CompressType);
                nsEx.WriteBuffer(buffer, 0);
                nsEx.Close();
                return bufferEx;
            }

            return buffer;
        }


        /// <summary>
        /// 对网络包进行解码处理
        /// </summary>
        /// <param name="data">buffer</param>
        /// <param name="len">长度</param>
        /// <returns></returns>
        public virtual NetPacket Decode(byte[] inBuffer, int len)
        {
            if (len < NetPacket.HeadExSize)
            {
                return null;
            }

            ushort netSize = 0;
            byte bEncryptType = 0;
            byte bCompressType = 0;
            byte[] buffer;
            if (m_bUseHeadEx)
            {
                NetStream nsEx = new NetStream(inBuffer, true);
                netSize = (ushort)nsEx.ReadInt16();
                // 长度不符合时返回
                if (len < netSize + NetPacket.NetPacketLenSize)
                { 
                    nsEx.Close();
                    return null;
                }

                bEncryptType = nsEx.ReadByte();
                bCompressType = nsEx.ReadByte();
                buffer = nsEx.ReadBuffer(netSize + NetPacket.NetPacketLenSize - NetPacket.HeadExSize);
                nsEx.Close();

                // 如果需要解压则解压
                if (0 != bCompressType)
                {
                    // 暂时不支持解压
                }
                
                // 如果需要解密则解密
                if (0 != bEncryptType)
                {
                    buffer = Decrypt(buffer, (EnumEncryptType)bEncryptType);
                }
            }
            else
            {
                buffer = inBuffer;
            }

            NetStream ns = new NetStream(buffer, true);
            ns.Seek(0);
            // 读取长度
            ushort length = (ushort)ns.ReadInt16();
            // 长度不够则返回空;
            if (length + NetPacket.NetPacketLenSize > len || length + NetPacket.NetPacketLenSize != buffer.Length )
            {
                ns.Close();
                return null;
            }

            NetPacket packet = GetDecodPaddingPacket();
            packet.NetSize = (netSize == 0) ? length : netSize;
            packet.EncryptType = bEncryptType;
            packet.CompressType = bCompressType;
            packet.RequestType = (EnumRequestType)ns.ReadByte();
            packet.SessionID = (uint)ns.ReadInt32();
            packet.ProtoType = (ushort)ns.ReadInt16();
            packet.ProtoID = (ushort)ns.ReadInt16();
            packet.DataBuffer = ns.ReadBuffer();
            ns.Close();

            if (packet.NetSize + NetPacket.NetPacketLenSize > len)
                return null;
            return packet;
        }


        public virtual byte[] Encrypt(byte[] buffer, EnumEncryptType eet = EnumEncryptType.XXTea)
        {
            switch (eet)
            {
                case EnumEncryptType.Aes:
                    buffer = crypt.Aes.Encrypt(buffer, m_sEncryptKey);
                    break;
                case EnumEncryptType.XXTea:
                default:
                    buffer = crypt.XXTea.Encrypt(buffer, m_sEncryptKey);
                    break;
            }
            return buffer;
        }

        public virtual byte[] Decrypt(byte[] buffer, EnumEncryptType eet = EnumEncryptType.XXTea)
        {
            switch (eet)
            {
                case EnumEncryptType.Aes:
                    buffer = crypt.Aes.Decrypt(buffer, m_sEncryptKey);
                    break;
                case EnumEncryptType.XXTea:
                default:
                    buffer = crypt.XXTea.Decrypt(buffer, m_sEncryptKey);
                    break;
            }
            return buffer;
        }

        /// <summary>
        /// 封装网络包
        /// </summary>
        /// <param name="_rule">使用一个NetRule构建一个网络包</param>
        /// <returns></returns>
        public abstract NetPacket Pack(NetMsg _rule);


        /// <summary>
        /// 解析网络包
        /// </summary>
        /// <param name="_packet">收到的网络包</param>
        /// <returns></returns>
        public abstract void Unpack(NetPacket _packet);


        /// <summary>
        /// 解析网络包需要的结构
        /// </summary>
        /// <returns>网络包类型</returns>
        public virtual NetPacket GetDecodPaddingPacket()
        {
            return new NetPacket();
        }
    }
}
